
#include <QDebug>
#include <QFileInfo>
#include <QTableView>
#include <QHeaderView>
#include <QAbstractItemView>
#include <QStandardItemModel>
#include <QStyledItemDelegate>
#include <QLabel>
#include <QIcon>

#include "logview.h"
#include "loadingwidget.h"

class LogViewStateDelegate : public QStyledItemDelegate
{
public:
    explicit LogViewStateDelegate(QAbstractItemView &itemview, QObject *parent = nullptr);
    ~LogViewStateDelegate();

    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
private:
    QAbstractItemView &view;
};

LogViewStateDelegate::LogViewStateDelegate(QAbstractItemView &itemview, QObject *parent) : QStyledItemDelegate(parent), view(itemview)
{}

LogViewStateDelegate::~LogViewStateDelegate()
{}

void LogViewStateDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    LogView::State state = static_cast<LogView::State>(index.data(Qt::UserRole).toInt());
    QRect rect = option.rect;
    QWidget *widget = nullptr;

    QSize icon_size = rect.size() - QSize(6, 6);

    auto CreateIconWidget = [=](const QString iconfile, const QSize &size, const QRect &rect) {
        QPixmap pixmap(iconfile);
        QPixmap pixmap_scaled = pixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        QLabel *icon_widget = new QLabel();
        icon_widget->setGeometry(rect);
        icon_widget->setAlignment(Qt::AlignCenter);
        icon_widget->setPixmap(pixmap_scaled);
        return (icon_widget);
    };

    if (!view.indexWidget(index)) {
        switch (state) {
        case LogView::Progress:
            // qDebug().noquote() << "Progress Rect:" << rect << "|" << icon_size;
            widget = new LoadingWidget(true, icon_size + QSize(1, 1), rect);
            break;
        case LogView::Success:
            // qDebug().noquote() << "Success Rect:" << rect;
            widget = CreateIconWidget(QLatin1String(":/icons/success.svg"), icon_size, rect);
            break;
        case LogView::Failure:
            // qDebug().noquote() << "Failure Rect:" << rect;
            widget = CreateIconWidget(QLatin1String(":/icons/failure.svg"), icon_size, rect);
            break;
        default:
            break;
        }
        if (widget) {
            view.setIndexWidget(index, widget);
        }
    }
}

class LogViewPrivate
{
    LogViewPrivate(LogView *parent = nullptr);
    ~LogViewPrivate();

    QStandardItemModel *model;

private:
    LogView * const q_ptr;
    Q_DECLARE_PUBLIC(LogView);
};

LogViewPrivate::LogViewPrivate(LogView *parent) : q_ptr(parent)
{
    model = new QStandardItemModel(parent);
}

LogViewPrivate::~LogViewPrivate()
{
    model->deleteLater();
}

LogView::LogView(QWidget *parent) : QTableView(parent), d_ptr(new LogViewPrivate(this))
{
    this->reset_default();

    // Table Delegate
    LogViewStateDelegate *logview_state = new LogViewStateDelegate(*this, this);
    this->setItemDelegateForColumn(Cols::Status, logview_state);

    Q_D(LogView);
    this->setModel(d->model);

    this->clear();
}

LogView::~LogView()
{}

void LogView::reset_default()
{
    this->setFocusPolicy(Qt::ClickFocus);
    this->setEditTriggers(QAbstractItemView::NoEditTriggers);
    this->setWordWrap(false);
    this->setShowGrid(false);
    this->setGridStyle(Qt::NoPen);
    this->setCornerButtonEnabled(false);
    QHeaderView *vheader = this->verticalHeader();
    vheader->setVisible(false);
    vheader->setDefaultSectionSize(20);
    vheader->setMinimumSectionSize(15);
    QHeaderView *hheader = this->horizontalHeader();
    hheader->setVisible(false);
    hheader->setDefaultSectionSize(20);
    hheader->setMinimumSectionSize(15);
}

void LogView::clear()
{
    Q_D(LogView);

    d->model->clear();
    d->model->setColumnCount(Cols::Count);
    d->model->setHorizontalHeaderItem(Cols::Contents, new QStandardItem(tr("Contents")));
    d->model->setHorizontalHeaderItem(Cols::Status, new QStandardItem(tr("Status")));

    QHeaderView *header = this->horizontalHeader();
    header->setSectionResizeMode(Cols::Contents, QHeaderView::Stretch);
    header->setSectionResizeMode(Cols::Status, QHeaderView::Fixed);

    this->reset_default();
}

QString LogView::addline(const QString &content, State status, QColor color, QFont::Weight weight, QFont::Style style)
{
    QString outstr;

    QStandardItem *item_content = new QStandardItem(content);
    QStandardItem *item_status = new QStandardItem();

    // Foreground Color
    if (color == Colors::Null()) {
        switch (status) {
        case Normal:
            item_content->setForeground(QBrush(Colors::Black()));
            item_status->setForeground(QBrush(Colors::Black()));
            outstr = content;
            break;
        case Error:
            item_content->setForeground(QBrush(Colors::Red()));
            item_status->setForeground(QBrush(Colors::Red()));
            outstr = content;
            break;
        case Progress:
            item_content->setForeground(QBrush(Colors::Black()));
            item_status->setForeground(QBrush(Colors::Black()));
            item_status->setData(status, Qt::UserRole);
            outstr = QString(QLatin1String("%1 ...")).arg(content);
            break;
        case Success:
            item_content->setForeground(QBrush(Colors::Black()));
            item_status->setForeground(QBrush(Colors::Green()));
            item_status->setData(status, Qt::UserRole);
            outstr = QString(QLatin1String("%1 ... [success]")).arg(content);
            break;
        case Failure:
            item_content->setForeground(QBrush(Colors::Red()));
            item_status->setForeground(QBrush(Colors::Red()));
            item_status->setData(status, Qt::UserRole);
            outstr = QString(QLatin1String("%1 ... [failure]")).arg(content);
            break;
        default:
            break;
        }
    } else {
        item_content->setForeground(QBrush(color));
    }

    // Font
    QFont font_content = item_content->font();
    font_content.setWeight(weight);
    font_content.setStyle(style);
    item_content->setFont(font_content);

    QFont font_status = item_status->font();
    font_status.setWeight(weight);
    font_status.setStyle(style);
    item_status->setFont(font_status);

    // Align
    item_status->setTextAlignment(Qt::AlignCenter);

    Q_D(LogView);
    int row = d->model->rowCount();
    d->model->setRowCount(row + 1);
    d->model->setItem(row, Cols::Status, item_status);
    d->model->setItem(row, Cols::Contents, item_content);

    return outstr;
}

QString LogView::addnormal(const QString &content)
{ return addline(content, State::Normal); }

QString LogView::adderror(const QString &content)
{ return addline(content, State::Error); }

QString LogView::addprogress(const QString &content)
{ return addline(content, State::Progress); }

QString LogView::addsuccess(const QString &content)
{ return addline(content, State::Success); }

QString LogView::addfailure(const QString &content)
{ return addline(content, State::Failure); }
